using System;
using System.Web.Mvc;
using System.Web.Security;
using DNT.RavenQA.Core.Extensions;
using DNT.RavenQA.Web.Infrastructure.Commands;
using DNT.RavenQA.Web.Infrastructure.Filters;
using DNT.RavenQA.Web.Infrastructure.QueryModel;
using DNT.RavenQA.Web.Infrastructure.Security;
using DNT.RavenQA.Web.ViewModels;
using DotNetOpenAuth.Messaging;
using log4net;
using Raven.Abstractions.Exceptions;
using Raven.Client;

namespace DNT.RavenQA.Web.Controllers
{
    public class UserController : ControllerBase
    {
        public UserController(IDocumentSession session,
                              ILog log,
                              IOpenIdAuthenticationService authenticationService)
            : base(session, log)
        {
            authenticationService.EnsureIsNotNull("authenticationService");
            _authenticationService = authenticationService;
        }

        private readonly IOpenIdAuthenticationService _authenticationService;

        [UnitOfWork]
        public ActionResult LogIn(String returnUrl = null)
        {
            var ru = returnUrl ?? FormsAuthentication.DefaultUrl;

            if (Request.IsAuthenticated)
                return RedirectFromLoginPage(ru);

            var result = _authenticationService.TryProcessOpenAuthResponse(HttpContext)
                ? RedirectFromLoginPage(ru)
                : View(new LogOnViewModel { ReturnUrl = ru });

            return result;
        }

        [HttpPost]
        public ActionResult LogIn(LogOnViewModel input)
        {
            ActionResult result;
            var ru = input.ReturnUrl ?? FormsAuthentication.DefaultUrl;

            try { result = _authenticationService.GetRedirectingResponse(input.ProviderName, ru); }
            catch (ProtocolException)
            {
                return View(new LogOnViewModel
                                {
                                    ErrorMessage = "Authentication server is not reachble."
                                });
            }

            return result.IsNotNull()
                ? result
                : View(new LogOnViewModel { ReturnUrl = input.ReturnUrl });
        }

        private ActionResult RedirectFromLoginPage(String retrunUrl = null)
        {
            return retrunUrl.IsNotNullOrWhiteSpace() && IsLocalUrl(retrunUrl)
                ? Redirect(retrunUrl)
                : (ActionResult)RedirectToAction("Index", "Question");
        }

        public ActionResult LogOut(String returnUrl)
        {
            FormsAuthentication.SignOut();
            return RedirectFromLoginPage(returnUrl);
        }

        public ActionResult Details(Int32 id)
        {
            return View(UserDetailsViewModel.Build(DocumentSession,
                                                   id,
                                                   CurrentUser,
                                                   new LatestUserQuestionsQuery(id)));
        }

        [UnitOfWork]
        [Authorize]
        public JsonResult Update(String userName)
        {
            DocumentSession.Advanced.UseOptimisticConcurrency = true;

            var command = new UpdateUserNameCommand(new UpdateUserNameCommand.Input
            {
                UserId = CurrentUser.Id,
                UserName = userName
            });

            try { command.Execute(DocumentSession); }
            catch (ConcurrencyException exc)
            {
                Log.Warn("A concurrency exception has been raied.", exc);
                return Json(new {NewValue = CurrentUser.Name, Success = false});
            }

            return Json(new { NewValue = userName, Success = true });
        }
    }
}